| GOOGL | |
|---|---|
| Date | |
| 2006-01-03 | 217.62 |
| 2006-01-04 | 222.62 |
| 2006-01-05 | 225.62 |
| 2006-01-06 | 232.83 |
| 2006-01-09 | 233.45 |
| ... | ... |
| 2015-12-24 | 765.84 |
| 2015-12-28 | 782.24 |
| 2015-12-29 | 793.96 |
| 2015-12-30 | 790.30 |
| 2015-12-31 | 778.01 |
2517 rows × 1 columns
\[ \small{ Sharpe = (R_p-R_f)\cdot{\sigma_j}^{-1}, \\ Sharpe - \text{współczynnik Sharpe'a}, \\ R_p - \text{zannualizowana średnia stopa zwrotu}, \\ R_f - \text{stopa zwrotu wolna od ryzyka}, \\ \sigma_j - \text{odchylenie standardowe portfela}.} \]
\[ \small{ Sortino = (R_j-R_f)\cdot{\sigma_d}^{-1}, \\ Sortino - \text{współczynnik Sortino}, \\ R_j - \text{zannualizowana średnia stopa zwrotu}, \\ R_f - \text{stopa zwrotu wolna od ryzyka}, \\ \sigma_d = \sqrt{\frac{1}{\sum_{i=1}^{n} \mathbf{1}_{\{R_i - R_f < 0\}}}\sum_{i=1}^{n} \min(0, R_i - R_f)^2} - \\ -\text{ odchylenie standardowe ujemnych zwrotów}. } \]
| GOOGL | |
|---|---|
| Date | |
| 2006-01-03 | 217.62 |
| 2006-01-04 | 222.62 |
| 2006-01-05 | 225.62 |
| 2006-01-06 | 232.83 |
| 2006-01-09 | 233.45 |
| ... | ... |
| 2015-12-24 | 765.84 |
| 2015-12-28 | 782.24 |
| 2015-12-29 | 793.96 |
| 2015-12-30 | 790.30 |
| 2015-12-31 | 778.01 |
2517 rows × 1 columns
Wskaźnik Sortino dla akcji Google
rfr = 0.04
target_return = 0
returns = data.pct_change()
negative_returns = returns.loc[returns['GOOGL'] < target_return]
expected_return = returns.mean()
annualized_return = (expected_return+1)**252 - 1
down_std = negative_returns.std()
sortino_ratio = (annualized_return - rfr) / (down_std*np.sqrt(252))Sortino dla akcji Google wynosi ok. 0.702.
Sharpe dla akcji Google wynosi ok. 0.488.
Największa procentowa strata od szczytu do dna.
Zależy od wybranego okna czasowego.
# Maksymalne spadki
roll_max = data.rolling(center=False, min_periods=1, window=252).max()
# Dzienny spadek w stosunku do maksimum
daily_draw_down = data/roll_max - 1.0
# Maksymalny dzienny spadek
max_daily_draw_down = daily_draw_down.rolling(center=False, min_periods=1, window=252).min()
# Wykres
plt.figure(figsize=(15,8))
plt.plot(data.index, daily_draw_down, label='Dzienne spadki')
plt.plot(data.index, max_daily_draw_down, label='Maksymalne spadki w okresie 252 dni')
plt.legend()
plt.show()positions = pd.read_csv('data/test_pos.csv', index_col=0)
positions.index = pd.to_datetime(positions.index)
benchmark = pd.read_csv('data/sp500.csv', index_col=0, skiprows=2)
benchmark.index = pd.to_datetime(benchmark.index, format='%Y-%m-%d', utc=True)
display(positions)| AMD | CERN | COST | DELL | GPS | INTC | MMM | cash | |
|---|---|---|---|---|---|---|---|---|
| index | ||||||||
| 2004-01-09 00:00:00+00:00 | 6961.92 | 21017.078750 | 7282.266152 | 21264.55188 | 7091.080020 | 21259.333890 | 21316.129606 | -6192.360298 |
| 2004-01-12 00:00:00+00:00 | 18198.58 | 18071.250000 | 17675.836401 | 10804.31924 | 10685.411865 | 17872.477480 | 10882.026400 | -3329.289887 |
| 2004-01-13 00:00:00+00:00 | 12060.86 | 11942.246250 | 12838.477446 | 16078.90380 | 16272.139000 | 12465.392511 | 12579.135758 | 4708.039735 |
| 2004-01-14 00:00:00+00:00 | 13102.40 | 15534.281250 | 14447.422640 | 15414.45080 | 15666.440185 | 14884.069620 | 13454.542620 | -2749.470030 |
| 2004-01-15 00:00:00+00:00 | 15518.40 | 14547.050000 | 14164.039680 | 14407.48813 | 14926.122619 | 14422.385864 | 13929.159049 | -2462.919316 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2009-12-24 00:00:00+00:00 | -1199.11 | 1316.857500 | 22778.660580 | -3562.47039 | 76601.638113 | 36280.269375 | 17740.890304 | 16350.679211 |
| 2009-12-28 00:00:00+00:00 | 589.80 | 673.840032 | 24170.422856 | -1765.41500 | 83143.517604 | 37499.607147 | 15692.520137 | 7641.201795 |
| 2009-12-29 00:00:00+00:00 | 292.50 | 334.920016 | 20993.396552 | 858.85252 | 94500.729990 | 50509.461877 | 7946.648597 | -6583.290764 |
| 2009-12-30 00:00:00+00:00 | 1681.56 | -167.179992 | 34934.764512 | 91207.82625 | 29751.588246 | 38052.304640 | -3926.109096 | -22234.787956 |
| 2009-12-31 00:00:00+00:00 | 22254.32 | 9975.240484 | 47781.667800 | 53022.51955 | 27393.148240 | 18850.582240 | -1934.275491 | -11938.952799 |
1506 rows × 8 columns
returns = positions.sum(axis=1).pct_change().dropna()
benchmark_rets = benchmark.iloc[:,0].pct_change().dropna()
benchmark_rets.rename('SP500', inplace=True)
pf.create_full_tear_sheet(returns, benchmark_rets=benchmark_rets)| Start date | 2004-01-12 | |
|---|---|---|
| End date | 2009-12-31 | |
| Total months | 71 | |
| Backtest | ||
| Annual return | 8.791% | |
| Cumulative returns | 65.404% | |
| Annual volatility | 26.26% | |
| Sharpe ratio | 0.45 | |
| Calmar ratio | 0.15 | |
| Stability | 0.00 | |
| Max drawdown | -60.391% | |
| Omega ratio | 1.09 | |
| Sortino ratio | 0.66 | |
| Skew | 0.14 | |
| Kurtosis | 5.88 | |
| Tail ratio | 0.99 | |
| Daily value at risk | -3.261% | |
| Alpha | 0.10 | |
| Beta | 0.84 | |
| Worst drawdown periods | Net drawdown in % | Peak date | Valley date | Recovery date | Duration |
|---|---|---|---|---|---|
| 0 | 60.39 | 2007-11-06 | 2009-03-09 | NaT | NaN |
| 1 | 24.10 | 2005-07-28 | 2006-09-07 | 2007-05-22 | 474 |
| 2 | 11.89 | 2004-06-25 | 2004-08-12 | 2004-11-05 | 96 |
| 3 | 10.87 | 2004-11-15 | 2005-04-18 | 2005-07-14 | 174 |
| 4 | 9.51 | 2007-07-16 | 2007-08-06 | 2007-09-13 | 44 |
| Stress Events | mean | min | max |
|---|---|---|---|
| Lehman | -0.27% | -4.70% | 4.11% |
| Aug07 | 0.32% | -2.96% | 2.92% |
| Mar08 | -0.43% | -3.26% | 3.36% |
| Sept08 | -0.68% | -4.38% | 4.08% |
| 2009Q1 | -0.36% | -5.02% | 3.39% |
| 2009Q2 | 0.74% | -4.03% | 6.13% |
| Low Volatility Bull Market | 0.01% | -6.07% | 6.43% |
| GFC Crash | -0.09% | -11.76% | 10.13% |
| Recovery | 0.35% | -4.03% | 6.01% |
# Mapowanie sektorów
sect_map = {'COST': 'Consumer Goods',
'INTC': 'Technology',
'CERN': 'Healthcare',
'GPS': 'Technology',
'MMM': 'Construction',
'DELL': 'Technology',
'AMD': 'Technology'}
pf.create_position_tear_sheet(returns,positions, sector_mappings=sect_map)| Top 10 long positions of all time | max |
|---|---|
| COST | 90.01% |
| DELL | 85.73% |
| CERN | 83.53% |
| MMM | 82.09% |
| INTC | 78.59% |
| AMD | 75.76% |
| GPS | 62.24% |
| Top 10 short positions of all time | max |
|---|---|
| AMD | -30.12% |
| DELL | -26.58% |
| CERN | -25.51% |
| MMM | -22.62% |
| GPS | -20.09% |
| INTC | -18.47% |
| COST | -16.44% |
| Top 10 positions of all time | max |
|---|---|
| COST | 90.01% |
| DELL | 85.73% |
| CERN | 83.53% |
| MMM | 82.09% |
| INTC | 78.59% |
| AMD | 75.76% |
| GPS | 62.24% |
…po angielsku modern portfolio theory lub mean–variance analysis.
…czyli Efficient frontier.
To zbiór porfeli, dla których nie istnieje inny portfel o wyższym oczekiwanym zwrocie przy tym samym odchyleniu standardowym zwrotu (ryzyku).
Szukamy takich wag, które pozwolą nam zminimalizować wariancję
\[ \min_{\mathbf{w}} = \mathbf{w}^T\Sigma\mathbf{w}. \]
Dla dobranych wag wartość oczekiwana zwrotu powinna odpowiadać ustalonemu poziomowi
\[ \mathbf{w}^T\mathbf{\mu} = \mu_p. \]
Wagi muszą sumować się do 1
\[ \mathbf{w}^T\mathbf{1}=1. \]
Źródło: https://inyova.ch/en/expertise/efficient-frontier-investment-theory/
Jak wyglądają nasze dane?
| AAPL | GE | AMD | WMT | BAC | T | XOM | BBY | PFE | JPM | |
|---|---|---|---|---|---|---|---|---|---|---|
| date | ||||||||||
| 1989-12-29 | 0.117203 | 0.352438 | 3.9375 | 3.486070 | 1.752478 | 2.365775 | 1.766756 | 0.166287 | 0.110818 | 1.827968 |
| 1990-01-02 | 0.123853 | 0.364733 | 4.1250 | 3.660858 | 1.766686 | 2.398184 | 1.766756 | 0.173216 | 0.113209 | 1.835617 |
| 1990-01-03 | 0.124684 | 0.364050 | 4.0000 | 3.660858 | 1.780897 | 2.356516 | 1.749088 | 0.194001 | 0.113608 | 1.896803 |
Importujemy potrzebne funkcje
Liczymy średnie zwroty dla danych…
Pierwsze 5 wyników dla średnich zwrotów
AAPL 0.294305
GE 0.136009
AMD 0.032850
WMT 0.120012
BAC 0.105540
dtype: float64
Liczymy macierz kowariancji zwrotów dla danych…
Pierwsze 5 wyników dla macierzy kowariancji
AAPL GE AMD WMT BAC
AAPL 0.207537 0.038348 0.084594 0.026599 0.046262
GE 0.038348 0.083109 0.048893 0.029263 0.063275
AMD 0.084594 0.048893 0.390586 0.027288 0.068712
WMT 0.026599 0.029263 0.027288 0.069092 0.030757
BAC 0.046262 0.063275 0.068712 0.030757 0.180192
Liczymy Efficient frontier…
Wybieramy porfel o rocznej stopie zwrotu 20%…
Wagi
AAPL: 0.16759
GE: 0.00000
AMD: 0.00000
WMT: 0.08029
BAC: 0.00000
T: 0.05185
XOM: 0.28483
BBY: 0.07526
PFE: 0.34018
JPM: 0.00000
Statystyki
Expected annual return: 20.0%
Annual volatility: 19.9%
Sharpe Ratio: 1.01
(0.1999999999999999, 0.19898336191007587, 1.0051091612894925)
Wybieramy porfel o najwyższym wskaźniku Sharpe’a…
Wagi
AAPL: 0.20430
GE: 0.00000
AMD: 0.00000
WMT: 0.03511
BAC: 0.00000
T: 0.00000
XOM: 0.26966
BBY: 0.09112
PFE: 0.39980
JPM: 0.00000
Statystyki
Expected annual return: 21.5%
Annual volatility: 21.3%
Sharpe Ratio: 1.01
(0.21532248096661105, 0.2127665321341155, 1.0120129270654485)
Wybieramy porfel o najmniejszej zmienności (odchyleniu standardowym zwrotów)…
Wagi
AAPL: 0.04306
GE: 0.05511
AMD: 0.00000
WMT: 0.21254
BAC: 0.00000
T: 0.21768
XOM: 0.31582
BBY: 0.01963
PFE: 0.13616
JPM: 0.00000
Statystyki
Expected annual return: 14.8%
Annual volatility: 17.7%
Sharpe Ratio: 0.84
(0.14823493562996323, 0.17710888575470818, 0.8369706296682669)
Nadajemy większe wagi nowym danym.
Statystyki
Expected annual return: 35.8%
Annual volatility: 23.3%
Sharpe Ratio: 1.54
(0.357758457877451, 0.23304517663697047, 1.5351463739357045)
… czyli wariancja ze zwrotów poniżej ustalonego benchmarku.
Pierwsze 5 wyników dla macierzy semikowariancji
AAPL GE AMD WMT BAC
AAPL 0.092904 0.025240 0.059902 0.021780 0.033612
GE 0.025240 0.036607 0.037300 0.017666 0.034130
AMD 0.059902 0.037300 0.178330 0.027033 0.052319
WMT 0.021780 0.017666 0.027033 0.031344 0.021281
BAC 0.033612 0.034130 0.052319 0.021281 0.080705
Markowitz, H.M. (March 1952). “Portfolio Selection”. The Journal of Finance. 7 (1): 77-91. doi:10.2307/2975974. JSTOR 2975974.
https://gregorygundersen.com/blog/2022/01/09/geometry-efficient-frontier/